Programação Web

Aula 20 - Armazenamento




Helder Jefferson Ferreira da Luz

helder.luz@ifpr.edu.br

Objetivos

  • Conhecer as diferentes formas de armazenamento de dados no navegador
  • Entender as diferenças entre LocalStorage, SessionStorage e Cookies
  • Aprender a salvar, ler e remover dados usando a Web Storage API
  • Entender o que é JSON e por que ele é essencial para armazenar objetos
  • Converter objetos JavaScript para JSON e vice-versa
  • Lidar com possíveis erros usando try...catch

Armazenamento em JavaScript

Há 5 formas de armazenamento de dados para a WEB:

  • Banco de dados (servidor)
  • Cookies
  • LocalStorage
  • SessionStorage
  • IndexedDB

Cookies

  • O que são? Pequenos pacotes de dados enviados entre o navegador e o servidor.
  • Uso principal: Gerenciamento de sessões (ex: login), personalização e rastreamento.
  • Por que não vamos focar? Baixa capacidade (4KB), sendo enviados em toda requisição ao servidor, o que pode ser ineficiente.

IndexedDB

  • O que é? Um banco de dados NoSQL de larga escala no navegador.
  • Uso principal: Aplicações web complexas que precisam armazenar grandes volumes de dados estruturados e funcionar offline.
  • Por que não vamos focar? Mais complexa e assíncrona. Tópico avançado que requer um estudo aprofundado.

Web Storage API: LocalStorage e SessionStorage

  • O que são? APIs que permitem armazenar pares de chave/valor no navegador.
  • Uso principal:
    • LocalStorage: Armazena dados sem data de expiração (ex: preferências do usuário, carrinho de compras).
    • SessionStorage: Armazena dados por sessão (os dados são perdidos quando a aba do navegador é fechada).
  • Por que vamos focar? Oferecem uma API simples e síncrona, maior capacidade de armazenamento (5-10MB) e não enviam dados ao servidor a cada requisição, sendo a solução moderna e ideal para a maioria dos casos de uso do lado do cliente.

Armazenamento - comparação

Cookies SessionStorage LocalStorage
Capacidade 4KB 5MB 5~10MB
Durabilidade Definido por configuração sessão Não expira
Local Cliente e servidor Cliente Cliente
Enviado ao servidor Enviado em cada requisição Não enviado com requisições Não enviado com requisições

LocalStorage e SessionStorage

A utilização do LocalStorage e SessionStorage é igual, diferenciando basicamente nas características mostradas na tabela anterior.

Ambos permitem acessar um objeto do tipo Storage, que possui os métodos:

  • storage.key()
  • storage.getItem()
  • storage.setItem()
  • storage.removeItem()
  • storage.clear()

Visualizando o Armazenamento

Você pode inspecionar o LocalStorage e o SessionStorage diretamente no seu navegador.

  1. Pressione F12 ou clique com o botão direito e vá em Inspecionar.
  2. Vá para a aba Application (ou Aplicação).
  3. No menu à esquerda, abra as seções Local Storage e Session Storage.

Isso é essencial para depurar e verificar se seus dados estão sendo salvos corretamente.

LocalStorage

  • localStorage.key(indice)
    • Retorna o nome da chave no índice específicado
  • localStorage.getItem(chave)
    • Retorna o valor armazenado na chave especificada.
  • localStorage.setItem(chave, valor)
    • Armazena o valor na chave especificada.
  • localStorage.removeItem(chave)
    • Remove a chave especificada.
  • localStorage.clear()
    • Esvazia todas as chaves.

LocalStorage

Exemplo
function populateStorage() {
    localStorage.setItem('bgcolor'document.getElementById('bgcolor').value);
    localStorage.setItem('font'document.getElementById('font').value);
    localStorage.setItem('image'document.getElementById('image').value);
  
    setStyles();
}

LocalStorage

Exemplo continuação
function setStyles() {
  var currentColor = localStorage.getItem('bgcolor');
  var currentFont = localStorage.getItem('font');
  var currentImage = localStorage.getItem('image');
  document.getElementById('bgcolor').value = currentColor;
  document.getElementById('font').value = currentFont;
  document.getElementById('image').value = currentImage;
  htmlElem.style.backgroundColor = '#' + currentColor;
  pElem.style.fontFamily = currentFont;
  imgElem.setAttribute('src', currentImage);
}

LocalStorage

LocalStorage e SessionStorage permite armazenar apenas String.

Para armazenar listas e objetos é necessário armazenar cada elemento utilizando uma chave diferente. Isso dificulta a utilização.

Outra forma é utilizar JSON.

JSON

JavaScript Object Notation

É um formato leve para troca de dados.

Permite fácil leitura por humanos e por máquinas.

Apesar do nome, é um dos padrões para envio e recebimento de dados utilizado em diversas linguagens.

JSON

Segue um padrão de par nome/valor.

Vetores são denotados por [ ]
Objetos são denotados por { }

JSON


JSON

JSON

JSON - Exemplo

function animal(tipo, nome, idade, peso, cor) {
  return { tipo: tipo, nome: nome, idade: idade, peso: peso, cor: cor }
}
const animais = []
animais.push(animal('Cachorro', 'Rex', 5, 20, 'Marrom'))
animais.push(animal('Gato', 'Luna', 3, 10, 'Preto'))
animais.push(animal('Coelho', 'Mingau', 2, 5, 'Branco'))
JSON
[
  {"tipo":"Cachorro","nome":"Rex","idade":5,"peso":20,"cor":"Marrom"},
  {"tipo":"Gato","nome":"Luna","idade":3,"peso":10,"cor":"Preto"},
  {"tipo":"Coelho","nome":"Mingau","idade":2,"peso":5,"cor":"Branco"}
]

JSON - Exemplo 2

{
    "squadName": "Super hero squad",
    "homeTown": "Metro City",
    "formed": 2016,
    "secretBase": "Super tower",
    "active": true,
    "members": [
        {
            "name": "Molecule Man",
            "age": 29,
            "secretIdentity": "Dan Jukes",
            "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
        },
        {
            "name": "Madame Uppercut",
            "age": 39,
            "secretIdentity": "Jane Wilson",
            "powers": ["Million tonne punch", "Damage resistance", "Superhuman reflexes"]
        },
        {
            "name": "Eternal Flame",
            "age": 1000000,
            "secretIdentity": "Unknown",
            "powers": ["Immortality", "Heat Immunity", "Inferno", "Teleportation", "Interdimensional travel"]
        }
    ]
}

JSON - Exemplo 2

JSON - Métodos no JavaScript

  • stringify()
    • Retorna o elemento como uma String no formato JSON
  • parse()
    • Analisa uma String como JSON e retorna o objeto
Exemplo
const animaisJSON = JSON.stringify(animais)
console.log(animaisJSON)
const animaisObj = JSON.parse(animaisJSON)
console.log(animaisObj)

Tratamento de Erros com try...catch

Nem todo código é à prova de falhas. E se a string não for um JSON válido? O parse irá quebrar.

Para evitar isso, há o bloco try...catch.

  • try: Envolve o código "perigoso" que pode gerar um erro.
  • catch: Captura o erro se ele acontecer, permitindo que o programa continue executando e que você trate a falha de forma elegante.

Tratamento de Erros com try...catch

Sintaxe
try {
  // Tente executar este código
  const resultado = operacaoPerigosa();
  console.log('Sucesso!', resultado);
} catch (erro) {
  // Se um erro ocorrer no bloco 'try', execute este código
  console.error('Ocorreu um erro:', erro.message);
}

try...catch com JSON.parse()

É uma boa prática sempre envolver JSON.parse() em um bloco try...catch ao ler dados do LocalStorage, pois os dados podem estar ausentes, corrompidos ou em um formato inesperado.

function carregarDados() {
  const dadosSalvos = localStorage.getItem('meusAnimais');
  let animais = [];

  if (dadosSalvos) {
    try { // Tenta converter a string para objeto.
      animais = JSON.parse(dadosSalvos);
    } catch (e) { // Se falhar, o JSON é inválido.
      console.error('Erro ao analisar dados salvos:', e);
    }
  }
  return animais;
}

Resumo e Boas Práticas

  • LocalStorage: Use para dados que devem persistir indefinidamente, como preferências do usuário (ex: tema escuro) ou um carrinho de compras.
  • SessionStorage: Use para dados temporários que só são relevantes enquanto a aba do navegador está aberta (ex: dados de um formulário de várias etapas).
  • Segurança: Nunca armazene informações sensíveis (senhas, tokens de autenticação, dados de cartão de crédito) no LocalStorage ou SessionStorage. Esses dados são facilmente acessíveis por qualquer script na página (ataques XSS).
  • JSON: Sempre use JSON.stringify para salvar objetos/arrays e JSON.parse (dentro de um try...catch) para lê-los.

Tópico Avançado: Expiração de Dados

O LocalStorage não tem um mecanismo de expiração nativo. É possível implementá-lo!

A estratégia é salvar o valor junto com um carimbo de data/hora (timestamp) de quando ele deve expirar.

Tópico Avançado: Expiração de Dados

function setWithExpiry(key, value, ttl) {
	const now = new Date()
	const item = {
		value: value,
		expiry: now.getTime() + ttl, // ttl em milissegundos
	}
	localStorage.setItem(key, JSON.stringify(item))
}

function getWithExpiry(key) {
	const itemStr = localStorage.getItem(key)
	if (!itemStr) return null

	const item = JSON.parse(itemStr)
	const now = new Date()

	if (now.getTime() > item.expiry) { // Verificando se expirou
		localStorage.removeItem(key)
		return null
	}
	return item.value
}

Documentação auxiliar

Dúvidas? 🤔

Exercícios

  1. Estando em qualquer página e usando o console, armazene o seu nome no sessionStorage e depois recupere-o. Atualize a página e tente ler novamente o valor. Feche e reabra a aba e verifique novamente se o valor continua armazenado.
  2. Crie uma página com 2 campos de texto e um botão. Ao clicar no botão, utilize o texto contido no primeiro campo como a chave e o texto do segundo campo como o valor para ser armazenado no localStorage. Teste a inserção de alguns valores e verifique se foram armazenados.
  3. Implemente um novo botão na página anterior que permita remover um registro com base no valor da chave.

Exercícios

  1. Implemente uma página para o exemplo da lista de animais. A página deve permitir ao usuário adicionar novos animais à lista.
    • Ao carregar a página, verifique se já existem animais no LocalStorage. Se sim, carregue-os e exiba na tela.
    • Ao adicionar um novo animal, a lista atualizada deve ser salva no LocalStorage (usando JSON) e exibida na página.
    function animal(tipo, nome, idade, peso, cor) {
      return { 
        tipo: tipo, 
        nome: nome, 
        idade: idade, 
        peso: peso, 
        cor: cor 
      }
    }
    

Adicione aqui uma imagem `devtools_storage.png` mostrando a aba Application

Isso torna nossa aplicação muito mais robusta.